package com.teatime.client.net.http;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;

import com.teatime.client.TLog;
import com.teatime.client.TeaTimeApp;

public class THttpClient {
	final private String UserAgent = "teatime";
	
	private String mUrl;
	private HttpUriRequest mRequest;
	private Context mContext;
	private THttpClientListener mListener;
	public THttpClient(String url, Context context, THttpClientListener listener) {
		mUrl = url;
		mContext = context;
		mRequest = null;
		mListener = listener;
	}
	
	public THttpClient(String url, Context context) {
		this(url, context, null);
		
	}
	
	public THttpClientListener getListener() {
		return mListener;
	}
	
	private HttpEntity getMulitPartEntity(HttpRequestParams params) {
		MultiPartEntity entity = new MultiPartEntity();
		Iterator<Entry<String, Object>> i;
		i = params.getParamsMap().entrySet().iterator();
		while(i.hasNext()) {
			Entry<String, Object> e = i.next();
			if (e.getValue() instanceof String) {
				entity.addPart(e.getKey(), (String)e.getValue());
			}
			else if (e.getValue() instanceof byte[]) {
				entity.addPart(e.getKey(), (byte[])e.getValue());
			}
			else if (e.getValue() instanceof FormFile) {
				entity.addPart(e.getKey(), (FormFile)e.getValue());
			}
		}
		return entity;
	}
	
	public HttpEntity getEncodedFormEntity(HttpRequestParams params) 
			throws UnsupportedEncodingException {
		List <NameValuePair> nvParams = new ArrayList <NameValuePair>();
		Iterator<Entry<String, Object>> i;
		i = params.getParamsMap().entrySet().iterator();
		while(i.hasNext()) {
			Entry<String, Object> e = i.next();
			nvParams.add(new BasicNameValuePair(e.getKey(), (String)e.getValue()));
		}
		return new UrlEncodedFormEntity(nvParams, HTTP.UTF_8);
	}
	
	private HttpEntity getEntity(HttpRequestParams params) 
			throws UnsupportedEncodingException {
		boolean multiPart = false;
		Iterator<Entry<String, Object>> i;
		i = params.getParamsMap().entrySet().iterator();
		while(i.hasNext()) {
			Entry<String, Object> e = i.next();
			if (!(e.getValue() instanceof String)) {
				multiPart = true;
				break;
			}
		}
		
		if (multiPart) {
			return getMulitPartEntity(params);
		}
		else {
			return getEncodedFormEntity(params);
		}
	}
	
	public HttpResponse execute() throws ClientProtocolException, IOException {
		TeaTimeApp app = (TeaTimeApp)(mContext.getApplicationContext());
		HttpParams httpParams = new BasicHttpParams();
        HttpProtocolParams.setUserAgent(httpParams, UserAgent);
        AbstractHttpClient client = new DefaultHttpClient(httpParams);
		client.setCookieStore(app.getCookieStore());
		//HttpContext httpContext = new BasicHttpContext();
		//httpContext.setAttribute(ClientContext.COOKIE_STORE, app.getCookieStore());
		
		HttpResponse httpResponse = client.execute(mRequest);
		/*cs = client.getCookieStore();
		for (i = 0; i < cs.getCookies().size(); i ++) {
			Cookie c = cs.getCookies().get(i);
			TLog.v("After Cookie: " + c.getDomain() + " : "
				+ c.getName() + " : "
				+ c.getValue());
		}*/
		return httpResponse;

	}
	
	private void asyncStart() {
		HttpClientTask task = new HttpClientTask(mContext, this);
		task.execute("");
	}
	
	public void post(HttpRequestParams params) throws UnsupportedEncodingException {
		HttpPost httpPost = new HttpPost(mUrl);
		httpPost.setEntity(getEntity(params));
		mRequest = httpPost;
		asyncStart();
	}
	
	class HttpClientTask extends AsyncTask<String, Integer, HttpResponse> {
		private Context mContext;
		private ProgressDialog mPDialog;
		private THttpClient mClient;
		private String mErrMsg;
		public HttpClientTask(Context context, THttpClient client) {
			mContext = context;
			mClient = client;
			mErrMsg = null;
		}
		
		@Override
        protected void onPreExecute() {
            //message.setText(R.string.task_started);
        	mPDialog = new ProgressDialog(mContext, 0);   
			mPDialog.setCancelable(true);
			mPDialog.setMax(100);
			mPDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
			mPDialog.show();
        }

		@Override
		protected HttpResponse doInBackground(String... params) {
			// TODO Auto-generated method stub
			try {
				return mClient.execute();
			} catch (ClientProtocolException e) {
				// TODO Auto-generated catch block
				mErrMsg = e.getMessage();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				mErrMsg = e.getMessage();
			}
			return null;
		}
		
		@Override
        protected void onPostExecute(HttpResponse response) {
            //message.setText(result);
			String resp = null;
			HttpEntity entity;

            mPDialog.dismiss();

            if (mClient.mListener != null && mErrMsg != null) {
            	mClient.mListener.onHttpError(mErrMsg);
			}
            
            if (response == null) {
            	return;
            }
            
			Header[] headers;
			headers = response.getAllHeaders();
			for (int i = 0; i < headers.length; i ++) {
				TLog.v(headers[i].getName() + ": " + headers[i].getValue());
			}

			try {
				entity = response.getEntity();
				resp = EntityUtils.toString(entity);
				TLog.v("body: \r\n" + resp);
				if (mClient.mListener != null) {
	            	mClient.mListener.onGetResponse(
	            			response.getStatusLine().getStatusCode(),
	            			resp);
				}
				mErrMsg = null;
				return;
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				mErrMsg = e.getMessage();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				mErrMsg = e.getMessage();
			}
			
			if (mClient.mListener != null && mErrMsg != null) {
            	mClient.mListener.onHttpError(mErrMsg);
			}
        }
		
		@Override
        protected void onCancelled() {
            super.onCancelled();
        }

		@Override
		protected void onProgressUpdate(Integer... values) {
			// message.setText(""+values[0]);
			mPDialog.setProgress(values[0]);
		}
	}
}
